package com.ruoyi.file.service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.ruoyi.file.config.MinioConfig;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;

/**
 * 视频优化服务
 * 
 * @author ruoyi
 */
@Service
public class VideoOptimizationService {
    
    private static final Logger log = LoggerFactory.getLogger(VideoOptimizationService.class);
    
    @Autowired
    private MinioConfig minioConfig;
    
    @Autowired
    private MinioClient minioClient;
    
    /**
     * 异步优化视频文件
     * 
     * @param originalFile 原始视频文件
     * @param originalUrl 原始文件URL
     * @return 优化后的文件URL
     */
    public CompletableFuture<String> optimizeVideoAsync(MultipartFile originalFile, String originalUrl) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return optimizeVideo(originalFile, originalUrl);
            } catch (Exception e) {
                log.error("视频优化失败: {}", e.getMessage(), e);
                // 如果优化失败，返回原始URL
                return originalUrl;
            }
        });
    }
    
    /**
     * 优化视频文件
     * 
     * @param originalFile 原始视频文件
     * @param originalUrl 原始文件URL
     * @return 优化后的文件URL
     */
    private String optimizeVideo(MultipartFile originalFile, String originalUrl) throws Exception {
        log.info("开始优化视频文件: {}", originalFile.getOriginalFilename());
        
        // 创建临时目录
        Path tempDir = Files.createTempDirectory("video_optimization_");
        Path originalPath = tempDir.resolve("original_" + originalFile.getOriginalFilename());
        Path optimizedPath = tempDir.resolve("optimized_" + originalFile.getOriginalFilename());
        
        try {
            // 保存原始文件到临时目录
            originalFile.transferTo(originalPath.toFile());
            
            // 检查文件大小，决定是否需要优化
            long fileSize = Files.size(originalPath);
            log.info("原始视频文件大小: {} MB", fileSize / (1024 * 1024));
            
            // 如果文件小于50MB，直接返回原始URL
            if (fileSize < 50 * 1024 * 1024) {
                log.info("视频文件较小，无需优化");
                return originalUrl;
            }
            
            // 执行视频优化
            boolean optimized = performVideoOptimization(originalPath, optimizedPath);
            
            if (optimized && Files.exists(optimizedPath)) {
                // 上传优化后的视频到MinIO
                String optimizedUrl = uploadOptimizedVideo(optimizedPath, originalFile.getOriginalFilename());
                
                // 删除原始文件（可选）
                // deleteOriginalVideo(originalUrl);
                
                log.info("视频优化完成，新URL: {}", optimizedUrl);
                return optimizedUrl;
            } else {
                log.warn("视频优化失败，使用原始文件");
                return originalUrl;
            }
            
        } finally {
            // 清理临时文件
            cleanupTempFiles(tempDir);
        }
    }
    
    /**
     * 执行视频优化
     * 
     * @param inputPath 输入文件路径
     * @param outputPath 输出文件路径
     * @return 是否优化成功
     */
    private boolean performVideoOptimization(Path inputPath, Path outputPath) {
        try {
            // 检查是否安装了FFmpeg
            if (!isFFmpegAvailable()) {
                log.warn("FFmpeg未安装，跳过视频优化");
                return false;
            }
            
            // 构建FFmpeg命令
            ProcessBuilder pb = new ProcessBuilder(
                "ffmpeg",
                "-i", inputPath.toString(),
                "-c:v", "libx264",           // 使用H.264编码
                "-crf", "23",                // 质量参数，23是较好的质量
                "-preset", "medium",         // 编码速度预设
                "-c:a", "aac",               // 音频编码
                "-b:a", "128k",              // 音频比特率
                "-movflags", "+faststart",   // 优化网络播放
                "-y",                        // 覆盖输出文件
                outputPath.toString()
            );
            
            log.info("执行FFmpeg命令: {}", String.join(" ", pb.command()));
            
            Process process = pb.start();
            
            // 等待进程完成，最多等待30分钟
            boolean finished = process.waitFor(30, TimeUnit.MINUTES);
            
            if (!finished) {
                log.error("FFmpeg进程超时");
                process.destroyForcibly();
                return false;
            }
            
            int exitCode = process.exitValue();
            if (exitCode == 0) {
                long originalSize = Files.size(inputPath);
                long optimizedSize = Files.size(outputPath);
                double compressionRatio = (double) (originalSize - optimizedSize) / originalSize * 100;
                
                log.info("视频优化成功 - 原始大小: {} MB, 优化后大小: {} MB, 压缩率: {:.2f}%", 
                    originalSize / (1024 * 1024), 
                    optimizedSize / (1024 * 1024), 
                    compressionRatio);
                
                return true;
            } else {
                log.error("FFmpeg执行失败，退出码: {}", exitCode);
                return false;
            }
            
        } catch (Exception e) {
            log.error("视频优化过程中发生错误: {}", e.getMessage(), e);
            return false;
        }
    }
    
    /**
     * 检查FFmpeg是否可用
     */
    private boolean isFFmpegAvailable() {
        try {
            ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-version");
            Process process = pb.start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            log.warn("FFmpeg检查失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 上传优化后的视频到MinIO
     */
    private String uploadOptimizedVideo(Path videoPath, String originalFileName) throws Exception {
        String fileName = "optimized_" + System.currentTimeMillis() + "_" + originalFileName;
        
        try (java.io.InputStream inputStream = Files.newInputStream(videoPath)) {
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object("videos/optimized/" + fileName)
                    .stream(inputStream, Files.size(videoPath), -1)
                    .contentType("video/mp4")
                    .build();
            
            minioClient.putObject(args);
            
            return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/videos/optimized/" + fileName;
        }
    }
    
    /**
     * 删除原始视频文件
     */
    private void deleteOriginalVideo(String originalUrl) {
        try {
            String objectName = originalUrl.substring(originalUrl.lastIndexOf("/") + 1);
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object("videos/" + objectName)
                    .build());
            log.info("已删除原始视频文件: {}", objectName);
        } catch (Exception e) {
            log.error("删除原始视频文件失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 清理临时文件
     */
    private void cleanupTempFiles(Path tempDir) {
        try {
            Files.walk(tempDir)
                .sorted((a, b) -> b.compareTo(a)) // 反向排序，先删除文件再删除目录
                .forEach(path -> {
                    try {
                        Files.deleteIfExists(path);
                    } catch (IOException e) {
                        log.warn("删除临时文件失败: {}", path, e);
                    }
                });
        } catch (IOException e) {
            log.error("清理临时目录失败: {}", tempDir, e);
        }
    }
}
